/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package mundo;

/**
 *
 * @author Yanire
 */
import XML.ObjetoXML;
import java.util.*;
import objetos.Aldea;
import objetos.Obstaculo;
import objetos.personajes.*;

public class Mapa {
    //Atributos

    private int m = 50;
    private int n = 20;
    private Celda matrizCelda[][];
    private String nombre;
    private ArrayList<Aldea> aldeas = new ArrayList<Aldea>();; //cuantas aldeas? depende de constantes mapas?

    // <editor-fold defaultstate="collapsed" desc="Constructor">



    public Mapa (int m, int n, String nombre){
        this.m = m;
        this.n = n;
        this.nombre = nombre;
        matrizCelda = new Celda[m][n];
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                matrizCelda[i][j] = new Celda();
            }
        }
    };

    public Mapa(int nivel, Bando[] bandos) {

        m += (nivel * 10);
        n += (nivel * 5);

        //Creo todas en vacio
        matrizCelda = new Celda[m][n];
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                matrizCelda[i][j] = new Celda();
            }
        }

        //inicializo arreglos que contienen obstaculos y posiciones de bandos y aldea
        ConstantesMapa constante = new ConstantesMapa(nivel);//SOLO PONGO PARA EL MAPA CERO
        nombre = constante.getNombre();//nombre del mapa
        int[] x;
        int[] y;
        int[] obs;
        int[] coordBandos;
        int[] aldeaX;
        int[] aldeaY;
        Obstaculo obstaculo;
        Aldea aldea;

        x = constante.getX();
        y = constante.getY();
        obs = constante.getObs();
        coordBandos = constante.getBandos();
        aldeaX = constante.getAldeasX();
        aldeaY = constante.getAldeasY();

        //Asigna obstaculos a mapa
        for (int i = 0; i < obs.length; i++) {
            obstaculo = new Obstaculo(obs[i]);
            matrizCelda[x[i]][y[i]] = new Celda(obstaculo);
        }

        //posiciono aldea
        //for para la asignacion de cada aldea

        for (int i = 0; i < aldeaX.length; i++) {
            aldea = new Aldea();
            aldea.setX(aldeaX[i]);
            aldea.setY(aldeaY[i]);
            aldeas.add(aldea);
            matrizCelda[aldeaX[i]][aldeaY[i]] = new Celda(aldea);
        }


        /*posicionar bandos

         *0:Patriota 1:Realista

         *coordBandos[0] primera coordenadaX
         *coordBandos[1] primera coordenadaY

         *asigna celda a bando patriota*/

        matrizCelda[coordBandos[0]][coordBandos[1]] = new Celda(bandos[0].getPersonajePrincipal());
        bandos[0].getPersonajePrincipal().setX(coordBandos[0]);
        bandos[0].getPersonajePrincipal().setY(coordBandos[1]);

        //asigna celda a bando realista

        matrizCelda[coordBandos[2]][coordBandos[3]] = new Celda(bandos[1].getPersonajePrincipal());
        bandos[1].getPersonajePrincipal().setX(coordBandos[2]);//segunda coordenadaX
        bandos[1].getPersonajePrincipal().setY(coordBandos[3]);//segunda coordenadaY

    }

    public Mapa(int nivel, Bando[] bandos, ArrayList<Aldea> aldeas) {

        m += (nivel * 10);
        n += (nivel * 5);

        //Creo todas en vacio
        matrizCelda = new Celda[m][n];
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                matrizCelda[i][j] = new Celda();
            }
        }

        //inicializo arreglos que contienen obstaculos y posiciones de bandos y aldea
        ConstantesMapa constante = new ConstantesMapa(nivel);//SOLO PONGO PARA EL MAPA CERO
        nombre = constante.getNombre();//nombre del mapa
        int[] x;
        int[] y;
        int[] obs;

        Obstaculo obstaculo;

        x = constante.getX();
        y = constante.getY();
        obs = constante.getObs();
        
        //Asigna obstaculos a mapa
        for (int i = 0; i < obs.length; i++) {
            obstaculo = new Obstaculo(obs[i]);
            matrizCelda[x[i]][y[i]] = new Celda(obstaculo);
        }

        //posiciono aldea
        //for para la asignacion de cada aldea

        for (int i = 0; i < 5; i++)
            matrizCelda[aldeas.get(i).getX()][aldeas.get(i).getY()] = new Celda(aldeas.get(i));

        //posicionar bandos
        //asigna celda a bando patriota
        for (int i=0; i<bandos[0].getPersonajes().size(); i++)
            matrizCelda[bandos[0].getPersonajes().get(i).getX()][bandos[0].getPersonajes().get(i).getY()] =
                new Celda(bandos[0].getPersonajes().get(i));

        //asigna celda a bando realista
        for (int i=0; i<bandos[1].getPersonajes().size(); i++)
            matrizCelda[bandos[1].getPersonajes().get(i).getX()][bandos[1].getPersonajes().get(i).getY()] =
                new Celda(bandos[1].getPersonajes().get(i));

    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Get & Set">
    public int getM() {
        return m;
    }

    public int getN() {
        return n;
    }

    public Celda getCelda(int x, int y) {
        return matrizCelda[x][y];
    }

    public String getNombre() {
        return nombre;
    }

    public ArrayList<Aldea> getAldeas() {
        return aldeas;
    }

    public void setM(int m) {
        this.m = m;
    }

    public void setN(int n) {
        this.n = n;
    }

    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

 public Personaje inicializarPersonaje(int tipoPersonaje) {
	Personaje soldado = null;

	switch (tipoPersonaje) {
	    case 0:
		soldado = new PersonajePrincipal();
		break;
	    case 1:
		soldado = new Artillero();
		break;
	    case 2:
		soldado = new SoldadoDeCaballeria();
		break;
	    case 3:
		soldado = new SoldadoDeInfanteria();
		break;
	    case 4:
		soldado = new Indigena();
		break;
	    case 5:
		soldado = new Rabona();
		break;
	}

	return soldado;
    }
    public void setCelda(Object objeto, Bando bandoP, Bando bandoR){
        
        ObjetoXML obj = (ObjetoXML) objeto;

        if(obj.clase.equals("Obstaculo")){
            Obstaculo obs = new Obstaculo(obj.tipoObstaculo);
            matrizCelda[obj.x][obj.y] = new Celda(obs);
        }

        if(obj.clase.equals("Aldea")){
            Aldea aldea = new Aldea();
            aldea.setX(obj.x);
            aldea.setY(obj.y);
            aldeas.add(aldea);
            matrizCelda[obj.x][obj.y] = new Celda(aldea);
        }

        if(obj.clase.equals("Personaje")){
            if (obj.bando==0){
		Personaje personaje = inicializarPersonaje(obj.tipoPersonaje);
		personaje.setBando(0);
                personaje.setX(obj.x);
                personaje.setY(obj.y);

		if(obj.tipoPersonaje == 0)
		    bandoP.setPersonajePrincipal((PersonajePrincipal)personaje);
		bandoP.getPersonajes().add(personaje);

                matrizCelda[obj.x][obj.y] = new Celda(personaje);
            }

            if (obj.bando==1){
		Personaje personaje = inicializarPersonaje(obj.tipoPersonaje);
		personaje.setBando(1);
                personaje.setX(obj.x);
                personaje.setY(obj.y);

		if(obj.tipoPersonaje == 0)
		    bandoR.setPersonajePrincipal((PersonajePrincipal)personaje);
		bandoR.getPersonajes().add(personaje);

                matrizCelda[obj.x][obj.y] = new Celda(personaje);
            }
        }
    }


    // </editor-fold>
    
    // <editor-fold defaultstate="collapsed" desc="Metodos Basicos">
    /**Devuelve verdadero si la celda está dentro de los límites del mapa.
     * @param x
     * @param y
     * @return
     */
    public boolean esCeldaDeMapa(int x, int y) {
        return (x >= 0 && y >= 0 && (x < m) && (y < n));
    }

    /**
     * Al realizar un movimiento, solo se modifica la celda si
     * va a ser ocupada por un batallon.
     * @param x
     * @param y
     * @param personajeJugada
     */
    public void modificaCelda(int x, int y, Personaje personajeJugada) {
        //Verificar necesidad de 3 parametro
        int xBat, yBat;

        xBat = personajeJugada.getX();
        yBat = personajeJugada.getY();
        matrizCelda[xBat][yBat] = new Celda();
        matrizCelda[x][y].setObjeto(personajeJugada);

        personajeJugada.setX(x);
        personajeJugada.setY(y);
    }

    public Aldea getAldea(int i) {
        return aldeas.get(i);
    }

    public boolean estaLleno() {
        boolean flag = true;

        for (int i = 0; i < m; i++) {
            for (int j = 0; i < n; j++) {
                flag = (flag && (getCelda(i, j).getObjeto() != null));
            }
        }

        return flag;
    }

    /**
     * Devuelve verdadero si no se puede colocar un personaje más
     * alrededor de la aldea.
     * @param aldea
     * @return
     */public boolean noRodearAldea(Aldea aldea) {
        //  Get a las posiciones actuales de la aldea
        int x = aldea.getX();
        int y = aldea.getY();
        boolean flag = true;

        for (int x1 = -1; x1 <= 1; x1++) {
            for (int y1 = -1; y1 <= 1; y1++) {
                if (esCeldaDeMapa(x + x1, y + y1)) {
                    flag = flag && (getCelda(x + x1, y + y1).getObjeto() != null);
                }
            }
        }
        return flag;
    }

    /**
     * Devuelve la dirección en la cual el personaje tiene una aldea adyacente.
     * @param batallon
     * @return La dirección de la aldea adyacente.
     */
    public int hayAldeaAdyacente(Personaje personaje) {
        //Get a las posiciones actuales de la aldea
        int x = personaje.getX();
        int y = personaje.getY();

        if (esCeldaDeMapa(x + 1, y)) {
            if ((getCelda(x + 1, y).getObjeto() != null)) {
                if (getCelda(x + 1, y).getObjeto() instanceof Aldea) {
                    return 3; //derecha
                }
            }
        }
        if (esCeldaDeMapa(x, y - 1)) {
            if ((getCelda(x, y - 1).getObjeto() != null)) {
                if (getCelda(x, y - 1).getObjeto() instanceof Aldea) {
                    return 12; //arriba
                }
            }
        }

        if (esCeldaDeMapa(x - 1, y)) {
            if ((getCelda(x - 1, y).getObjeto() != null)) {
                if (getCelda(x - 1, y).getObjeto() instanceof Aldea) {
                    return 9; //izquierda
                }
            }
        }

        if (esCeldaDeMapa(x, y + 1)) {
            if ((getCelda(x, y + 1).getObjeto() != null)) {
                if (getCelda(x, y + 1).getObjeto() instanceof Aldea) {
                    return 6;//abajo
                }
            }
        }
        //Si no tiene ninguna aldea adyacente devuelve 0
        return 0;
    }

    /**
     * Devuelve la aldea adyacente en esa dirección al personaje pasado
     * como parámetro.
     * @param personaje
     * @param dir
     * @return
     */
    public Aldea getAldeaAdyacente(Personaje personaje, int dir) {
        //Obtiene las coordenadas del personaje
        int x = personaje.getX();
        int y = personaje.getY();
        Aldea aldea = null;

        switch (dir) {
            case 3:
                aldea = (Aldea) (getCelda(x + 1, y).getObjeto());
                break;
            case 6:
                aldea = (Aldea) (getCelda(x, y + 1).getObjeto());
                break;
            case 9:
                aldea = (Aldea) (getCelda(x - 1, y).getObjeto());
                break;
            case 12:
                aldea = (Aldea) (getCelda(x, y - 1).getObjeto());
                break;
        }
        return aldea;
    }

    /**
     * Devuelve verdadero si hay una aldea adyacente al personaje en esa
     * dirección o falso en caso contraio.
     * @param personaje
     * @param direccion
     * @return
     */
    public boolean aldeaAdyacente(Personaje personaje, int direccion) {
        //  Get a las posiciones actuales de la aldea
        int x = personaje.getX();
        int y = personaje.getY();

        switch (direccion) {
            case 3:
                x++;
                break;
            case 6:
                y++;
                break;
            case 9:
                x--;
                break;
            case 12:
                y--;
                break;
        }

        if (esCeldaDeMapa(x, y)) {
            if ((getCelda(x, y).getObjeto() != null)) {
                if (getCelda(x, y).getObjeto() instanceof Aldea) {
                    return true;
                }
            }
        }
        //Si no hay aldea
        return false;
    }

    /**
     * Devuelve la dirección en la cual el personaje tiene un enemigo adyacente.
     * @param personaje
     * @return
     */
    public int hayEnemigoAdyacente(Personaje personaje) {
        //  Get a las posiciones actuales de la aldea
        int x = personaje.getX();
        int y = personaje.getY();

        if (esCeldaDeMapa(x + 1, y)) {
            if ((getCelda(x + 1, y).getObjeto() != null)) {
                if (getCelda(x + 1, y).getObjeto() instanceof Personaje) {
                    Personaje personajeAd = (Personaje) (getCelda(x + 1, y).getObjeto());
                    if (personaje.getBando() != personajeAd.getBando()) {
                        return 3; //derecha
                    }
                }
            }
        }

        if (esCeldaDeMapa(x, y - 1)) {
            if ((getCelda(x, y - 1).getObjeto() != null)) {
                if (getCelda(x, y - 1).getObjeto() instanceof Personaje) {
                    Personaje personajeAd = (Personaje) (getCelda(x, y - 1).getObjeto());
                    if (personaje.getBando() != personajeAd.getBando()) {
                        return 12; //arriba
                    }
                }
            }
        }

        if (esCeldaDeMapa(x - 1, y)) {
            if ((getCelda(x - 1, y).getObjeto() != null)) {
                if (getCelda(x - 1, y).getObjeto() instanceof Personaje) {
                    Personaje personajeAd = (Personaje) (getCelda(x - 1, y).getObjeto());
                    if (personaje.getBando() != personajeAd.getBando()) {
                        return 9; //izquierda
                    }
                }
            }
        }

        if (esCeldaDeMapa(x, y + 1)) {
            if ((getCelda(x, y + 1).getObjeto() != null)) {
                if (getCelda(x, y + 1).getObjeto() instanceof Personaje) {
                    Personaje personajeAd = (Personaje) (getCelda(x, y + 1).getObjeto());
                    if (personaje.getBando() != personajeAd.getBando()) {
                        return 6;//abajo
                    }
                }
            }
        }
        return 0;//no hay enemigo
    }

    /**
     * Devuelve el enemigo adyacente en esa dirección al personaje pasado
     * como parámetro.
     * @param personaje
     * @param dir
     * @return
     */
    public Personaje getEnemigoAdyacente(Personaje personaje, int dir) {
        //  Get a las posiciones actuales de la aldea
        int x = personaje.getX();
        int y = personaje.getY();
        Personaje personajeAd = null;

        switch (dir) {
            case 3:
                personajeAd = (Personaje) (getCelda(x + 1, y).getObjeto());
                break;
            case 6:
                personajeAd = (Personaje) (getCelda(x, y + 1).getObjeto());
                break;
            case 9:
                personajeAd = (Personaje) (getCelda(x - 1, y).getObjeto());
                break;
            case 12:
                personajeAd = (Personaje) (getCelda(x, y - 1).getObjeto());
                break;

        }
        return personajeAd;
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Métodos para funcionar con hilos">

    // </editor-fold>
}
